#pragma once
#include "CGIPrefix.h"
#include "CGIResource.h"
#include "CGIContext.h"
#include "PipelineStateCache.h"
#include "Runtime/Utils/SmartPtr.h"

namespace Alice{
    class CGICommandListBase;
    class DynamicCGI{
    public:
        virtual bool Init() = 0;
        virtual DynamicCGI* GetNonValidationRHI() { return this; }
        //  must be called from the main thread.
        // FlushType: Thread safe
        virtual SmartPtr<CGIViewport> CGICreateViewport(void* WindowHandle, uint32 SizeX, uint32 SizeY, bool bIsFullscreen, EPixelFormat PreferredPixelFormat) = 0;
        virtual SmartPtr<CGITexture> CGIGetViewportBackBuffer(CGIViewport* Viewport,uint32&inImageIndex) = 0;
        virtual ICGICommandContext* CGIGetDefaultContext() = 0;
        /**
        * @param ResourceArray - An optional pointer to a resource array containing the resource's data.
        */
        virtual CGIBuffer* RHICreateBuffer(CGICommandListBase& RHICmdList, CGIBufferDesc const& Desc, ECGIAccess ResourceState, CGIResourceCreateInfo& CreateInfo) = 0;
        virtual CGIGraphicsPipelineState* RHICreateGraphicsPipelineState(const FGraphicsPipelineStateInitializer& Initializer) = 0;
        // FlushType: Wait RHI Thread
        virtual CGIVertexShader* RHICreateVertexShader(const char*inShaderPath, unsigned char* inCode, int32 inCodeDataLen) = 0;
        // FlushType: Wait RHI Thread
        virtual CGIPixelShader* RHICreatePixelShader(const char*inShaderPath, unsigned char* inCode, int32 inCodeDataLen) = 0;
        // FlushType: Wait RHI Thread
        virtual CGIVertexDeclaration* RHICreateVertexDeclaration(const VertexDeclarationElementList& Elements) = 0;
    };
}
extern Alice::DynamicCGI*gDynamicCGI;
template<typename TCGI>
FORCEINLINE TCGI* CastDynamicRHI(Alice::DynamicCGI* InDynamicRHI)
{
    return static_cast<TCGI*>(InDynamicRHI->GetNonValidationRHI());
}
template<typename TCGI>
FORCEINLINE TCGI* GetDynamicRHI()
{
    return CastDynamicRHI<TCGI>(gDynamicCGI);
}
extern "C" void CGIInit();
FORCEINLINE Alice::SmartPtr<Alice::CGIViewport> CGICreateViewport(void* WindowHandle, uint32 SizeX, uint32 SizeY, bool bIsFullscreen, Alice::EPixelFormat PreferredPixelFormat)
{
    return gDynamicCGI->CGICreateViewport(WindowHandle, SizeX, SizeY, bIsFullscreen, PreferredPixelFormat);
}
FORCEINLINE Alice::SmartPtr<Alice::CGITexture> RHIGetViewportBackBuffer(Alice::CGIViewport* Viewport,uint32&inImageIndex)
{
    return gDynamicCGI->CGIGetViewportBackBuffer(Viewport,inImageIndex);
}
FORCEINLINE Alice::ICGICommandContext* CGIGetDefaultContext()
{
    return gDynamicCGI->CGIGetDefaultContext();
}
FORCEINLINE Alice::CGIGraphicsPipelineState* CGICreateGraphicsPipelineState(const Alice::FGraphicsPipelineStateInitializer& Initializer)
{
    return gDynamicCGI->RHICreateGraphicsPipelineState(Initializer);
}
FORCEINLINE Alice::CGIVertexShader* CGICreateVertexShader(const char*inShaderPath, unsigned char* inCode, int32 inCodeByteLen)
{
    return gDynamicCGI->RHICreateVertexShader(inShaderPath,inCode, inCodeByteLen);
}
FORCEINLINE Alice::CGIPixelShader* CGICreatePixelShader(const char*inShaderPath, unsigned char* inCode, int32 inCodeByteLen)
{
    return gDynamicCGI->RHICreatePixelShader(inShaderPath,inCode, inCodeByteLen);
}
/** Before using this directly go through PipelineStateCache::GetOrCreateVertexDeclaration() */
FORCEINLINE Alice::CGIVertexDeclaration* RHICreateVertexDeclaration(const Alice::VertexDeclarationElementList& Elements)
{
    return gDynamicCGI->RHICreateVertexDeclaration(Elements);
}
Alice::DynamicCGI* PlatformCreateDynamicCGI();